package config

import (
	"errors"
	"fmt"
	"runtime"
)

type errorConfigure struct {
	msg string
}

func newError(msg string) error {
	err := newErrorOut(msg,3)
	if err != nil {
		return err
	}
	err = &errorConfigure{
		msg:msg,
	}
	return err
}

func newErrorOut(msg string,skip int) error {
	msg,err := caller(skip,msg)
	if err != nil {
		return err
	}
	err = &errorConfigure{
		msg:msg,
	}
	return err
}

func caller(skip int,msg string) (string,error) {
	pc,file,line,ok := runtime.Caller(skip)
	if !ok {
		return "",errors.New("call function stack fail in caller function\n")
	}
	f := runtime.FuncForPC(pc)
	return fmt.Sprintf("%s:%d %s::%s",file,line,f.Name(),msg),nil
}

func withError(err error,msg string) error {
	err_,ok := err.(*errorConfigure)
	if !ok {
		return newErrorOut(fmt.Sprintf("%s\n%s",err.Error(),msg),3)
	}
	msg,argErr := caller(2,msg)
	if argErr != nil {
		err_.AppendMsg(argErr.Error())
	} else {
		err_.AppendMsg(msg)
	}

	return err_
}

func (err *errorConfigure) Error() string {
	return err.msg
}

func (err *errorConfigure) AppendMsg(msg string) error {
	if err == nil {
		return nil
	}
	err.msg = fmt.Sprintf("%s\n%s",err.msg,msg)
	return err
}